home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / dvi2xx / tfm.c < prev    next >
C/C++ Source or Header  |  1994-04-24  |  8KB  |  256 lines

  1. /* tfm.c -- read tfm widths resident font support in dvilj. */
  2.  
  3. #include "config.h" /* for STRSIZE and tfm_info_type, at least */
  4. #include <stdio.h>
  5.  
  6.  
  7. #ifdef vms
  8. #include <ssdef.h>
  9. #include <stsdef.h>
  10. #define getenv vms_getenv
  11. #endif
  12.  
  13. /* Defined in dvi2xx.c. */
  14. extern long NoSignExtend ();
  15. #define TFM_GET_TWO()  NoSignExtend (tfm_fp, 2)
  16. #define TFM_GET_FOUR() NoSignExtend (tfm_fp, 4)
  17. extern char* TFMpath;
  18. extern bool G_quiet;
  19. extern void Warning();
  20.  
  21. /* Defined in xmalloc.c. */
  22. extern void *xmalloc ();
  23.  
  24.  
  25.  
  26. /* Read N words (N * 4 bytes) from TFM_FP and return it in *OUTBUF, unless
  27.    OUTBUF==NULL, in which case throw them away. */
  28.  
  29. static void
  30. tfm_get_n (tfm_fp, nwords, outbuf)
  31.     FILE *tfm_fp;
  32.     unsigned nwords;
  33.     void **outbuf;
  34. {
  35.   unsigned n = nwords * 4;
  36.   void *buf = (void *) xmalloc (n);
  37.  
  38.   if (fread (buf, n, 1, tfm_fp) != 1) {
  39.     fprintf (stderr, "dvi2xx: Could not read %u bytes from TFM file.\n", n);
  40.     exit (1);
  41.   }
  42.  
  43.   /* If OUTBUF is null, free what we just read, else return it. */
  44.   if (outbuf) {
  45.     *outbuf = buf;
  46.   } else {
  47.     free (buf);
  48.   }
  49. }
  50.  
  51.  
  52. /* Read a string in BCPL format from DATA into STR, and terminate with a
  53.    null byte. First byte of DATA says how many characters follow.
  54.    Assume STR is long enough.  */
  55.  
  56. static void
  57. get_bcpl (data, str)
  58.     unsigned char *data;
  59.     unsigned char *str;
  60. {
  61.   unsigned length;
  62.   
  63.   for (length = *(data ++); length; length --) {
  64.     *(str ++) = *(data ++);
  65.   }
  66.  *str = 0;
  67. }
  68.  
  69. /* Header word 18:
  70.      2 bytes: "KN" for Karl and Norm---this identifies our extensions
  71.      1 byte : 1 if proportional, 0 otherwise
  72.      1 byte : reserved (to extend the style, if necessary)
  73.    Header word 19:
  74.      2 bytes: PCL style selection number
  75.      1 byte : reserved (to extend weight, if necessary)
  76.      1 byte : weight (signed, 2's complement, valid -7 to +7)
  77.    Header word 20:
  78.      2 bytes: reserved (to extend typeface id, if necessary)
  79.      2 bytes: PCL typeface selection number
  80.    
  81.    The first (BigEndian) byte of header word #18 is DATA[0].
  82.    Assume DATA is long enough for everything we might try to read. */
  83.  
  84. static bool
  85. get_pcl_info (data, spacing, style, weight, typeface_id)
  86.     unsigned char *data;
  87.     unsigned *spacing;
  88.     unsigned *style;
  89.     int *weight;
  90.     unsigned *typeface_id;
  91. {
  92.   /* No magic number for our extensions => forget it. */
  93.   if (data[0] != 'K' && data[1] != 'N')
  94.     return FALSE;
  95.  
  96.   *spacing = data[(0* 4) + 2]; /* Third byte of first word. */
  97.   
  98.   /* First two bytes of second word. */
  99.   *style = (data[(1 * 4)] << 8) + data[(1 * 4) + 1];
  100.   
  101.   /* Last byte of second word, signed two-complement. */
  102.   *weight = data[(1 * 4) + 3];
  103.   if (*weight >= 128) *weight -= 256;
  104.   
  105.   /* Effectively all four bytes of third word. */
  106.   *typeface_id = (data[(2 * 4) + 0] << 24) + (data[(2 * 4) + 1] << 16)
  107.                + (data[(2 * 4) + 2] << 8)  + (data[(2 * 4) + 3]);
  108.  
  109.   return TRUE;
  110. }
  111.  
  112. /* If the TFM file NAME exists, set the elements of RET and return true.
  113.    Otherwise, return false.  */
  114.  
  115. bool
  116. tfm_read_info (name, ret)
  117.     char *name;
  118.     tfm_info_type *ret;
  119. {
  120.   /* Don't use a structure for this, since then it might occupy more
  121.      than the exactly four bytes that we need. */
  122.   unsigned char *char_info;
  123.   char full_name[STRSIZE];
  124.   FILE *tfm_fp;
  125.   unsigned char *header_data;
  126.   unsigned char *width_raw; /* array of 1-byte data */
  127.   unsigned long *width_table; /* array of 4-byte fixes */
  128.   unsigned i;
  129.   unsigned lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np;
  130.  
  131.  
  132.   if (findfile(TFMpath, name, NULL, full_name, TRUE, 0)) {
  133.  
  134.     /* fprintf(stderr,"full_name=<%s>\n", full_name);*/
  135.     tfm_fp = fopen (full_name, READ_BINARY);
  136.     if (tfm_fp == NULL) {
  137.       /* this can happen, if the calculation for max number of open
  138.        * files has to be corrected
  139.        */
  140.       fprintf(stderr,"Error: file <%s> could not be opened\n", full_name);
  141.       return FALSE;
  142.     }
  143.   } else {
  144.     Warning("tfm file %s.tfm not found on path <%s>\n", name, TFMpath);
  145.     return FALSE;
  146.   }
  147.  
  148.   (void) TFM_GET_TWO ();   /* word length of file */
  149.   lh = TFM_GET_TWO ();     /* words of header data */
  150.   bc = TFM_GET_TWO ();     /* smallest character code */
  151.   ec = TFM_GET_TWO ();     /* largest character code */
  152.   nw = TFM_GET_TWO ();     /* words in width table */
  153.   nh = TFM_GET_TWO ();     /* words in height table */
  154.   nd = TFM_GET_TWO ();     /* words in depth table */
  155.   ni = TFM_GET_TWO ();     /* words in italic correction table */
  156.   nl = TFM_GET_TWO ();     /* words in lig/kern table */
  157.   nk = TFM_GET_TWO ();     /* words in kern table */
  158.   ne = TFM_GET_TWO ();     /* words in extensible char table */
  159.   np = TFM_GET_TWO ();     /* words of font parameter data */
  160.  
  161.   tfm_get_n (tfm_fp, lh, &header_data);
  162.   /* Only two headerbyte words are required by the TFM format, so don't
  163.      insist on all this extra stuff. */
  164.   if (lh > 2) {
  165.     get_bcpl (header_data + (2 * 4), ret->coding_scheme);
  166.   } else {
  167.     ret->coding_scheme[0] = 0;
  168.   }
  169.   
  170.   if (lh > 12) {
  171.     get_bcpl (header_data + (12 * 4), ret->family);
  172.   } else {
  173.     ret->family[0] = 0;
  174.   }
  175.  
  176.   /* Sorry for the convoluted logic. The idea is that if the family
  177.      is HPAUTOTFM, we better have our extensions -- so if we don't
  178.      have enough header words, or if we don't find what we need in
  179.      the header words, something's seriously wrong, and we shouldn't
  180.      claim to have succeeded at reading a good TFM file.  */
  181.  
  182.   if (strcmp (ret->family, "HPAUTOTFM") == 0
  183.       && (lh < 20
  184.           || !get_pcl_info (&(header_data[18 * 4]),
  185.                             &ret->spacing, &ret->style, &ret->weight,
  186.                             &ret->typeface_id))) {
  187.     return FALSE;
  188.   }
  189.  
  190. /*
  191.   if (strcmp (ret->family, "HPAUTOTFM") == 0) {
  192.     if (lh < 20 || !get_pcl_info (&(header_data[18 * 4]),
  193.                   &ret->spacing, &ret->style, &ret->weight,
  194.                   &ret->typeface_id)) {
  195.       fclose (tfm_fp);
  196.       return FALSE;
  197.     }
  198.   } else {
  199.     if (strcmp (ret->family, "UNSPECIFIED") == 0) {
  200.       Warning("font family for %s is UNSPECIFIED; did you run dvicopy?",
  201.           full_name);
  202.     }
  203.   }
  204. */
  205.  
  206.   /* Initialize our returned array of widths to zero, since the TFM file
  207.      need not contain info for all character codes. */
  208.   for (i = 0; i < bc; i++) {
  209.     ret->widths[i] = 0;
  210.   }
  211.   for (i = ec + 1; i < 256; i++) {
  212.     ret->widths[i] = 0;
  213.   }
  214.   
  215.   /* The char_info is one word (four bytes) for each character in the font. */
  216.   tfm_get_n (tfm_fp, ec - bc + 1, &char_info);
  217.   
  218.   /* The width table is just nw words. */
  219.   tfm_get_n (tfm_fp, nw, &width_raw);
  220.   width_table = (unsigned long *) xmalloc (nw * 4);
  221.  
  222.   /* But the width table contains four-byte numbers, so have to convert
  223.      from BigEndian to host order. */
  224.   for (i = 0; i < nw; i++) {
  225.     unsigned byte_offset = i * 4;
  226.     unsigned b1 = width_raw[byte_offset];
  227.     unsigned b2 = width_raw[byte_offset + 1];
  228.     unsigned b3 = width_raw[byte_offset + 2];
  229.     unsigned b4 = width_raw[byte_offset + 3];
  230.     width_table[i] = (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
  231.   }
  232.  
  233.   /* For each character, retrieve and store the TFM width. */
  234.   for (i = bc; i <= ec; i++) {
  235.     unsigned char w_i = char_info[(i - bc) * 4];
  236.     ret->widths[i] = width_table[w_i];
  237.   }
  238.  
  239.   /* Throw away everything up to the second font parameter. (Could just
  240.      seek, but I don't want to pull in the include files, etc.) */
  241.   if (np >= 2) {
  242.     tfm_get_n (tfm_fp, nh + nd + ni + nl + nk + ne + 1, NULL);
  243.     ret->interword = TFM_GET_FOUR ();
  244.   } else {
  245.     ret->interword = 0;
  246.   }
  247.  
  248.   free (header_data);
  249.   free (char_info);
  250.   free (width_raw);
  251.   free (width_table);
  252.   
  253.   fclose (tfm_fp);
  254.   return TRUE;
  255. }
  256.